package cn.com.mjsoft.framework.persistence.core.support;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import cn.com.mjsoft.framework.persistence.core.annotation.Table;
import cn.com.mjsoft.framework.persistence.exception.DataAccessException;
import cn.com.mjsoft.framework.persistence.exception.EntitySqlFieldNotExistException;
import cn.com.mjsoft.framework.persistence.exception.RegisterSqlStringException;
import cn.com.mjsoft.framework.util.StringUtil;

/**
 * Java pojo与数据库对应表之间的桥梁，其基本的sql语句和相关信息可以在这里获得
 * 
 * @author mjsoft
 * 
 */
public class EntitySqlBridge
{
    private static final Logger log = Logger.getLogger( EntitySqlBridge.class );

    /**
     * 由数据库负责生成
     */
    public static final int DB_IDENTITY = -1;

    /**
     * 由第三方生成
     */
    public static final int ASSIGNED = -2;

    /**
     * 无ID
     */
    public static final int NO_KEY_ID = -3;

    private static final String DEFAULT_LIST_SELECT_COL = "ci.contentId";

    private String pojoClazz = "";

    private String selectSql = "";

    private String insertSql = "";

    private String updateSql = "";

    private String deleteSql = "";

    private String selectColumn = "";

    private String listSelectColumn = "";

    private int insertParamCount;

    private int updateParamCount;

    private String table;

    private String identification;

    private int idMode;

    private Map<String, Field> fieldMapper = new LinkedHashMap<String, Field>();

    public EntitySqlBridge()
    {

    }

    public EntitySqlBridge( Object tf )
    {
        registerEntity( tf );
    }

    public EntitySqlBridge( String tableName, String idName, String tmpName, String prefixName,
        List<String> columnNameList, Set<String> innerColumnSet, int idMode )
    {
        registerTable( tableName, idName, tmpName, prefixName, columnNameList, innerColumnSet,
            idMode );
    }

    private void registerEntity( Object tf )
    {
        Table ta = tf.getClass().getAnnotation( Table.class );

        if( ta == null )
        {
            throw new RegisterSqlStringException( "无法加载相关表信息,请检查VO对象注解是否存在:"
                + tf.getClass().getName() );
        }

        if( StringUtil.isStringNull( ta.name() ) )
            throw new RegisterSqlStringException( "没有提供pojo相匹配的表名" );

        if( ta.idMode() != NO_KEY_ID )
        {
            if( StringUtil.isStringNull( ta.name() ) )
                throw new RegisterSqlStringException( "没有提供相关表的主键名称" );
        }

        Class<?> targetClazz = tf.getClass();

        pojoClazz = targetClazz.getName();

        log.info( "当前注册的Pojo类型 ： " + pojoClazz );

        Field[] declaredFields = targetClazz.getDeclaredFields();

        /**
         * ID和表名
         */
        table = ta.name();

        identification = ta.id();

        idMode = ta.idMode();

        /**
         * DELETE SQL
         */
        StringBuffer deleteBuf = new StringBuffer( "delete from " );
        deleteBuf.append( ta.name() );
        deleteBuf.append( " where " );
        deleteBuf.append( ta.id() );
        deleteBuf.append( "=?" );

        /**
         * SELECT INSERT UPDATE SQL 以及field映射
         */
        StringBuffer selectBuf = new StringBuffer( "select" );
        StringBuffer insertBuf = new StringBuffer( "insert into " );
        insertBuf.append( ta.name() );
        StringBuffer insertBufValues = new StringBuffer( ") values (" );
        insertBuf.append( " (" );
        StringBuffer updateBuf = new StringBuffer( "update " );
        updateBuf.append( ta.name() );
        updateBuf.append( " set " );
        int insertParamCount = 0;
        int updateParamCount = 0;

        for ( int i = 0; i < declaredFields.length; i++ )
        {
            Field f = declaredFields[i];
            int modifier = f.getModifiers();
            if( !( ( Modifier.isStatic( modifier ) || Modifier.isFinal( modifier ) ) ) )
            {
                fieldMapper.put( declaredFields[i].getName(), declaredFields[i] );

                insertParamCount++;
                updateParamCount++;
                insertBufValues.append( "?" );
                boolean notId = false;
                if( !ta.id().equals( f.getName() ) )
                {
                    notId = true;
                    updateBuf.append( f.getName() );
                    updateBuf.append( "=?" );
                }
                selectBuf.append( " " );
                selectBuf.append( f.getName() );
                insertBuf.append( f.getName() );

                // if( ( i + 1 ) != declaredFields.length )
                selectBuf.append( "," );
                insertBuf.append( ", " );
                insertBufValues.append( ", " );

                if( notId )
                {
                    updateBuf.append( ", " );
                }

            }
        }

        selectBuf.deleteCharAt( selectBuf.lastIndexOf( "," ) );
        insertBuf.deleteCharAt( insertBuf.lastIndexOf( "," ) );
        updateBuf.deleteCharAt( updateBuf.lastIndexOf( "," ) );
        insertBufValues.deleteCharAt( insertBufValues.lastIndexOf( "," ) );

        log.info( "field映射 : " + fieldMapper );

        insertBufValues.append( ")" );
        insertBuf.append( insertBufValues );
        updateBuf.append( "where " );
        updateBuf.append( ta.id() );
        updateBuf.append( "=?" );
        selectBuf.append( " from " );
        selectBuf.append( ta.name() );
        selectBuf.append( " where " );
        selectBuf.append( ta.id() );
        selectBuf.append( "=?" );
        log.debug( "[TARGET POJO : ]" + tf + "[ SELECT SQL :]" + selectBuf.toString() );

        String insert = null;
        if( ta.idMode() == EntitySqlBridge.DB_IDENTITY )
        {
            this.insertParamCount = --insertParamCount;
            insert = StringUtil.replaceString( insertBuf.toString(), ta.id() + ", ", "", false,
                false );
            insert = StringUtil.replaceString( insert, ", ? )", ")", false, false );
        }
        else
        {
            this.insertParamCount = insertParamCount;
            insert = insertBuf.toString();
        }
        this.updateParamCount = updateParamCount;

        selectSql = selectBuf.toString();
        insertSql = insert;
        updateSql = updateBuf.toString();
        deleteSql = deleteBuf.toString();

        // System.out.println( "[ SELECT SQL :]" + selectBuf.toString() );
        // System.out.println( "[ INSERT SQL :]" + insert );
        // System.out.println( "[ DELETE SQL :]" + deleteBuf.toString() );
        // System.out.println( "[ UPDATE SQL :]" + updateBuf.toString() );
        log.info( "[TARGET VO TYPE :]" + tf.getClass() );
        log.info( "[ SELECT SQL :]" + selectSql );
        log.info( "[ INSERT SQL :]" + insertSql );
        log.info( "[ DELETE SQL :]" + deleteSql );
        log.info( "[ UPDATE SQL :]" + updateSql );
    }

    private void registerTable( String tableName, String idName, String tmpName, String prefixName,
        List<String> columnNameList, Set<String> innerColumnSet, int idMode )
    {
        if( tableName == null || idName == null || columnNameList == null )
        {
            return;
        }

        log.info( "当前注册的数据表全名 ： " + tableName );

        /**
         * DELETE SQL
         */
        StringBuffer deleteBuf = new StringBuffer( "delete from " );
        deleteBuf.append( tableName.trim() );
        deleteBuf.append( " where " );
        deleteBuf.append( idName.trim() );
        deleteBuf.append( "=?" );

        /**
         * SELECT INSERT UPDATE SQL 以及field映射
         */
        StringBuffer selectBuf = new StringBuffer( "select" );
        StringBuffer selectColumnBuf = new StringBuffer( "" );
        StringBuffer insertBuf = new StringBuffer( "insert into " );
        insertBuf.append( tableName );
        StringBuffer insertBufValues = new StringBuffer( ") values (" );
        insertBuf.append( " (" );
        StringBuffer updateBuf = new StringBuffer( "update " );
        updateBuf.append( tableName );
        updateBuf.append( " set " );
        int insertParamCount = 0;
        int updateParamCount = 0;

        String cloumnName;
        for ( int i = 0; i < columnNameList.size(); i++ )
        {
            cloumnName = ( String ) columnNameList.get( i );

            // 内部业务字段不需要存在在insert 和 update中
            if( !innerColumnSet.contains( cloumnName ) )
            {
                insertParamCount++;
                updateParamCount++;

                insertBufValues.append( "?" );
            }

            boolean notId = false;

            if( !idName.equals( cloumnName ) && !innerColumnSet.contains( cloumnName ) )
            {
                notId = true;
                updateBuf.append( cloumnName );
                updateBuf.append( "=?" );
            }

            if( cloumnName.indexOf( "contentId" ) == -1 )
            {
                if( i + 2 != columnNameList.size() )
                {
                    selectColumnBuf.append( tmpName + "." + cloumnName + " as "
                        + StringUtil.replaceString( cloumnName, prefixName, "", false, true )
                        + ", " );
                }
                else
                {
                    selectColumnBuf.append( tmpName + "." + cloumnName + " as "
                        + StringUtil.replaceString( cloumnName, prefixName, "", false, true ) );
                }
            }

            selectBuf.append( " " );
            selectBuf.append( cloumnName );

            if( !innerColumnSet.contains( cloumnName ) )
            {
                insertBuf.append( cloumnName );
                insertBuf.append( ", " );
                insertBufValues.append( ", " );
            }

            // if( ( i + 1 ) != declaredFields.length )
            selectBuf.append( "," );

            if( notId )
            {
                updateBuf.append( ", " );
            }

        }

        selectBuf.deleteCharAt( selectBuf.lastIndexOf( "," ) );
        insertBuf.deleteCharAt( insertBuf.lastIndexOf( "," ) );
        int updateIndex = updateBuf.lastIndexOf( "," );

        if( updateIndex != -1 )
        {
            updateBuf.deleteCharAt( updateBuf.lastIndexOf( "," ) );
        }
        else
        {
            // 没有任何字段的情况下
            updateBuf = new StringBuffer( "" );
        }

        insertBufValues.deleteCharAt( insertBufValues.lastIndexOf( "," ) );

        log.info( "field映射 : " + fieldMapper );

        insertBufValues.append( ")" );
        insertBuf.append( insertBufValues );
        updateBuf.append( "where " );
        updateBuf.append( idName );
        updateBuf.append( "=?" );
        selectBuf.append( " from " );
        selectBuf.append( tableName );
        selectBuf.append( " where " );
        selectBuf.append( idName );
        selectBuf.append( "=?" );
        log.debug( "[TARGET TABLE : ]" + tableName + "[ SELECT SQL :]" + selectBuf.toString() );

        String insert = null;
        if( idMode == EntitySqlBridge.DB_IDENTITY )
        {
            this.insertParamCount = --insertParamCount;
            insert = StringUtil.replaceString( insertBuf.toString(), idName + ", ", "", false,
                false );
            insert = StringUtil.replaceString( insert, ", ? )", ")", false, false );
        }
        else
        {
            this.insertParamCount = insertParamCount;
            insert = insertBuf.toString();
        }
        this.updateParamCount = updateParamCount;

        selectSql = selectBuf.toString();
        insertSql = insert;
        updateSql = updateBuf.toString();
        deleteSql = deleteBuf.toString();
        selectColumn = selectColumnBuf.toString();
        listSelectColumn = DEFAULT_LIST_SELECT_COL;
    }

    public String getDeleteSql()
    {
        return deleteSql;
    }

    public String getInsertSql()
    {
        return insertSql;
    }

    public String getPojoClazz()
    {
        return pojoClazz;
    }

    public String getSelectSql()
    {
        return selectSql;
    }

    public String getUpdateSql()
    {
        return updateSql;
    }

    public int getInsertParamCount()
    {
        return insertParamCount;
    }

    public int getUpdateParamCount()
    {
        return updateParamCount;
    }

    public String getTable()
    {
        return table;
    }

    public String getIdentification()
    {
        return identification;
    }

    public int getIdMode()
    {
        return idMode;
    }

    public String getSelectColumn()
    {
        return selectColumn;
    }

    public String getListSelectColumn()
    {
        return listSelectColumn;
    }

    public void setListSelectColumn( String listSelectColumn )
    {
        this.listSelectColumn = listSelectColumn;
    }

    public Field getPojoSqlField( String name ) throws DataAccessException
    {
        Field fe = ( Field ) fieldMapper.get( name );
        if( fe == null )
        {
            log.error( "指定的字段不在当前注册实体信息中,key : " + name );
            throw new EntitySqlFieldNotExistException( "指定的字段不在当前注册实体信息中" );
        }
        return ( Field ) fieldMapper.get( name );
    }

    public Iterator<String> getFieldNameIterator()
    {
        return fieldMapper.keySet().iterator();
    }

}
